﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Diagnostics;

namespace Ict.DataAccess.Linq
{
    public class Insertable<T> : Modifiable, IQueryable<T>
    {
        // private LambdaExpression selectClause;

        public bool Insert<TElement>(TElement entity)
        {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.Append("INSERT INTO ");
            stringBuilder.Append(TableMapper<TElement>.TableName);
            stringBuilder.Append('(');
            List<string> propertyList = BuildFieldList<TElement>(stringBuilder, selectClause);
            stringBuilder.Append(')');

            stringBuilder.Append(" VALUES(");
            BuildFieldValues(stringBuilder, propertyList, entity); 
            stringBuilder.Append(')');

            string sql = stringBuilder.ToString();
            Debug.WriteLine(sql);

            int n = 0;
            using (Executor exec = (Provider as ModifiableProvider).Executor)
            {
                n = exec.Insert(entity, sql);
            }
            return (n > 0);
        }

        private void BuildFieldValues<TElement>(StringBuilder stringBuilder, List<string> propertyList, TElement entity)
        {
            IEnumerator<string> istr = propertyList.GetEnumerator();
            if (istr.MoveNext())
            {
                DmlEncoder encoder = DataContext.Current.CreateSqlEncoder();
                Type entityType = typeof(TElement);
                do
                {
                    object o = entityType.GetProperty(istr.Current).GetValue(entity, null);
                    stringBuilder.Append(encoder.EncodeValue(o));
                    if (!istr.MoveNext())
                        break;
                    stringBuilder.Append(',');
                } while (true);
            }
        }

        private List<string> BuildFieldList<TElement>(StringBuilder stringBuilder, 
            System.Linq.Expressions.Expression expression)
        {
            if (expression == null
                || expression.NodeType == ExpressionType.MemberAccess
                && (expression as MemberExpression).Type == this.ElementType)
            {
                IEnumerator<string> istr = TableMapper<T>.TableFieldMap.Values.GetEnumerator();
                if (istr.MoveNext())
                {
                    do
                    {
                        stringBuilder.Append(istr.Current);
                        if (!istr.MoveNext())
                            break;
                        stringBuilder.Append(',');
                    } while (true);
                }
                return TableMapper<T>.TableFieldMap.Keys.ToList();
            }
            else if (expression.NodeType == ExpressionType.Lambda)
            {
                return BuildFieldList<TElement>(stringBuilder, (expression as LambdaExpression).Body);
            }
            else if (expression.NodeType == ExpressionType.New)
            {
                List<string> result = new List<string>();

                IEnumerator<Expression> iarg = ((NewExpression)expression).Arguments.GetEnumerator();
                if (iarg.MoveNext())
                {
                    do
                    {
                        string fieldName = null;
                        if (iarg.Current.NodeType == ExpressionType.MemberAccess)
                        {
                            string propertyName = (iarg.Current as MemberExpression).Member.Name;
                            fieldName = TableMapper<TElement>.TableFieldMap[propertyName];
                            if (fieldName != null)
                            {
                                stringBuilder.Append(fieldName);
                                result.Add(propertyName);
                            }
                        }
                        if (!iarg.MoveNext())
                            break;
                        if (fieldName != null)
                            stringBuilder.Append(',');
                    } while (true);
                }
                return result;
            }
            else
                throw new NotSupportedException("不支持的表达式，无法导出字段列表。");
        }

        //public bool Insert<TElement>(Expression<Func<TElement, T>> selectClause, TElement entity)
        //{
        //    this.selectClause = selectClause;
        //    return Insert<TElement>(entity);
        //}

        public bool Insert<TElement>(T entity, Expression<Func<T, TElement>> selectClause)
        {
            this.selectClause = selectClause;
            return Insert<T>(entity);
        }

        internal override void AddExpression(string methodName, System.Linq.Expressions.Expression expression)
        {
            if (methodName == "Select")
            {
                selectClause = (expression as UnaryExpression).Operand as LambdaExpression;
            }
            else
                throw new NotSupportedException(string.Format("不支持的方法调用：{0}", methodName));
        }

        internal override Modifiable Clone<TElement>()
        {
            Insertable<TElement> modifier = new Insertable<TElement>();
            modifier.Provider = this.Provider;

            return modifier;
        }

        internal override Modifiable Clone()
        {
            return Clone<T>();
        }

        public override Type ElementType
        {
            get { return typeof(T); }
        }

        #region IEnumerable<T> 成员

        public new IEnumerator<T> GetEnumerator()
        {
            return (IEnumerator<T>)GetEnumerator();
        }

        #endregion
    }
}
